// Graph structure implementation
use codegraph_core::{
    CodeNode, CodeEdge, NodeId, EdgeId, NodeType, EdgeType, Result, CodeGraphError,
    GraphQuery, QueryResult,
};
use crate::{GraphNode, GraphEdge};
use std::collections::{HashMap, HashSet};
use std::sync::{Arc, RwLock};
use std::time::Instant;
use petgraph::graph::{DiGraph, NodeIndex, EdgeIndex};
use petgraph::visit::EdgeRef;
use dashmap::DashMap;

use serde::{Serialize, Deserialize};
use tracing::info;

/// Main code graph structure with efficient storage and querying
#[derive(Debug, Clone)]
pub struct CodeGraph {
    /// Internal petgraph for efficient graph operations
    graph: Arc<RwLock<DiGraph<NodeId, EdgeId>>>,
    /// Node storage with fast lookup
    nodes: Arc<DashMap<NodeId, Arc<RwLock<GraphNode>>>>,
    /// Edge storage with fast lookup
    edges: Arc<DashMap<EdgeId, Arc<RwLock<GraphEdge>>>>,
    /// Node index mapping for petgraph
    node_indices: Arc<DashMap<NodeId, NodeIndex>>,
    /// Edge index mapping for petgraph
    edge_indices: Arc<DashMap<EdgeId, EdgeIndex>>,
    /// Language-based node grouping
    language_nodes: Arc<DashMap<String, HashSet<NodeId>>>,
    /// Type-based node grouping
    type_nodes: Arc<DashMap<NodeType, HashSet<NodeId>>>,
    /// Graph metadata
    metadata: GraphMetadata,
}

/// Graph metadata and statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphMetadata {
    /// Creation timestamp
    pub created_at: chrono::DateTime<chrono::Utc>,
    /// Last modification timestamp
    pub modified_at: chrono::DateTime<chrono::Utc>,
    /// Graph version for change tracking
    pub version: u64,
    /// Total number of nodes
    pub node_count: usize,
    /// Total number of edges
    pub edge_count: usize,
    /// Languages present in the graph
    pub languages: HashSet<String>,
    /// Node types present in the graph
    pub node_types: HashSet<NodeType>,
    /// Edge types present in the graph
    pub edge_types: HashSet<EdgeType>,
    /// Graph statistics
    pub stats: GraphStats,
}

/// Detailed graph statistics
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct GraphStats {
    /// Average degree (connections per node)
    pub average_degree: f64,
    /// Graph density (actual edges / possible edges)
    pub density: f64,
    /// Number of connected components
    pub connected_components: usize,
    /// Diameter of the graph (longest shortest path)
    pub diameter: Option<usize>,
    /// Clustering coefficient
    pub clustering_coefficient: f64,
}

impl Default for GraphStats {
    fn default() -> Self {
        Self {
            average_degree: 0.0,
            density: 0.0,
            connected_components: 0,
            diameter: None,
            clustering_coefficient: 0.0,
        }
    }
}

impl CodeGraph {
    /// Create a new empty code graph
    pub fn new() -> Self {
        let now = chrono::Utc::now();
        Self {
            graph: Arc::new(RwLock::new(DiGraph::new())),
            nodes: Arc::new(DashMap::new()),
            edges: Arc::new(DashMap::new()),
            node_indices: Arc::new(DashMap::new()),
            edge_indices: Arc::new(DashMap::new()),
            language_nodes: Arc::new(DashMap::new()),
            type_nodes: Arc::new(DashMap::new()),
            metadata: GraphMetadata {
                created_at: now,
                modified_at: now,
                version: 1,
                node_count: 0,
                edge_count: 0,
                languages: HashSet::new(),
                node_types: HashSet::new(),
                edge_types: HashSet::new(),
                stats: GraphStats::default(),
            },
        }
    }

    /// Add a node to the graph
    pub fn add_node(&mut self, node: GraphNode) -> Result<NodeId> {
        let node_id = node.id();

        // Add to petgraph
        let mut graph = self.graph.write().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire graph write lock")
        })?;
        let node_index = graph.add_node(node_id);
        drop(graph);

        // Store mappings
        self.node_indices.insert(node_id, node_index);

        // Update language grouping
        let language = node.language().to_string();
        self.language_nodes
            .entry(language.clone())
            .or_insert_with(HashSet::new)
            .insert(node_id);

        // Update type grouping
        let node_type = node.node_type().clone();
        self.type_nodes
            .entry(node_type.clone())
            .or_insert_with(HashSet::new)
            .insert(node_id);

        // Store the node
        self.nodes.insert(node_id, Arc::new(RwLock::new(node)));

        // Update metadata
        self.metadata.modified_at = chrono::Utc::now();
        self.metadata.version += 1;
        self.metadata.node_count += 1;
        self.metadata.languages.insert(language);
        self.metadata.node_types.insert(node_type);

        Ok(node_id)
    }

    /// Add an edge to the graph
    pub fn add_edge(&mut self, edge: GraphEdge) -> Result<EdgeId> {
        let edge_id = edge.id();
        let source_id = edge.source();
        let target_id = edge.target();
        let edge_type = edge.edge_type().clone();

        // Verify that both nodes exist
        if !self.nodes.contains_key(&source_id) {
            return Err(CodeGraphError::graph_update_error(
                format!("Source node {} not found", source_id)
            ));
        }
        if !self.nodes.contains_key(&target_id) {
            return Err(CodeGraphError::graph_update_error(
                format!("Target node {} not found", target_id)
            ));
        }

        // Get node indices
        let source_index = *self.node_indices.get(&source_id).ok_or_else(|| {
            CodeGraphError::graph_update_error(format!("Source node index {} not found", source_id))
        })?;
        let target_index = *self.node_indices.get(&target_id).ok_or_else(|| {
            CodeGraphError::graph_update_error(format!("Target node index {} not found", target_id))
        })?;

        // Add to petgraph
        let mut graph = self.graph.write().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire graph write lock")
        })?;
        let edge_index = graph.add_edge(source_index, target_index, edge_id);
        drop(graph);

        // Store mappings
        self.edge_indices.insert(edge_id, edge_index);

        // Store the edge
        self.edges.insert(edge_id, Arc::new(RwLock::new(edge)));

        // Update metadata
        self.metadata.modified_at = chrono::Utc::now();
        self.metadata.version += 1;
        self.metadata.edge_count += 1;
        self.metadata.edge_types.insert(edge_type);

        Ok(edge_id)
    }

    /// Remove a node from the graph
    pub fn remove_node(&mut self, node_id: NodeId) -> Result<bool> {
        // Check if node exists
        let node = self.nodes.get(&node_id).ok_or_else(|| {
            CodeGraphError::graph_update_error(format!("Node {} not found", node_id))
        })?;

        let node_guard = node.read().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire node read lock")
        })?;
        let language = node_guard.language().to_string();
        let node_type = node_guard.node_type().clone();
        drop(node_guard);
        drop(node);

        // Get node index
        let node_index = *self.node_indices.get(&node_id).ok_or_else(|| {
            CodeGraphError::graph_update_error(format!("Node index {} not found", node_id))
        })?;

        // Remove from petgraph (this also removes connected edges)
        let mut graph = self.graph.write().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire graph write lock")
        })?;
        let removed_node = graph.remove_node(node_index);
        drop(graph);

        if removed_node.is_some() {
            // Remove from storage
            self.nodes.remove(&node_id);
            self.node_indices.remove(&node_id);

            // Update language grouping
            if let Some(mut lang_nodes) = self.language_nodes.get_mut(&language) {
                lang_nodes.remove(&node_id);
            }

            // Update type grouping
            if let Some(mut type_nodes) = self.type_nodes.get_mut(&node_type) {
                type_nodes.remove(&node_id);
            }

            // Update metadata
            self.metadata.modified_at = chrono::Utc::now();
            self.metadata.version += 1;
            self.metadata.node_count = self.metadata.node_count.saturating_sub(1);

            Ok(true)
        } else {
            Ok(false)
        }
    }

    /// Remove an edge from the graph
    pub fn remove_edge(&mut self, edge_id: EdgeId) -> Result<bool> {
        // Check if edge exists
        if !self.edges.contains_key(&edge_id) {
            return Ok(false);
        }

        // Get edge index
        let edge_index = *self.edge_indices.get(&edge_id).ok_or_else(|| {
            CodeGraphError::graph_update_error(format!("Edge index {} not found", edge_id))
        })?;

        // Remove from petgraph
        let mut graph = self.graph.write().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire graph write lock")
        })?;
        let removed_edge = graph.remove_edge(edge_index);
        drop(graph);

        if removed_edge.is_some() {
            // Remove from storage
            self.edges.remove(&edge_id);
            self.edge_indices.remove(&edge_id);

            // Update metadata
            self.metadata.modified_at = chrono::Utc::now();
            self.metadata.version += 1;
            self.metadata.edge_count = self.metadata.edge_count.saturating_sub(1);

            Ok(true)
        } else {
            Ok(false)
        }
    }

    /// Get a node by ID
    pub fn get_node(&self, node_id: NodeId) -> Option<Arc<RwLock<GraphNode>>> {
        self.nodes.get(&node_id).map(|entry| entry.clone())
    }

    /// Get an edge by ID
    pub fn get_edge(&self, edge_id: EdgeId) -> Option<Arc<RwLock<GraphEdge>>> {
        self.edges.get(&edge_id).map(|entry| entry.clone())
    }

    /// Get all nodes
    pub fn nodes(&self) -> Vec<Arc<RwLock<GraphNode>>> {
        self.nodes.iter().map(|entry| entry.value().clone()).collect()
    }

    /// Get all edges
    pub fn edges(&self) -> Vec<Arc<RwLock<GraphEdge>>> {
        self.edges.iter().map(|entry| entry.value().clone()).collect()
    }

    /// Get nodes by language
    pub fn nodes_by_language(&self, language: &str) -> Vec<Arc<RwLock<GraphNode>>> {
        if let Some(node_ids) = self.language_nodes.get(language) {
            node_ids.iter()
                .filter_map(|id| self.nodes.get(id).map(|entry| entry.clone()))
                .collect()
        } else {
            Vec::new()
        }
    }

    /// Get nodes by type
    pub fn nodes_by_type(&self, node_type: NodeType) -> Vec<Arc<RwLock<GraphNode>>> {
        if let Some(node_ids) = self.type_nodes.get(&node_type) {
            node_ids.iter()
                .filter_map(|id| self.nodes.get(id).map(|entry| entry.clone()))
                .collect()
        } else {
            Vec::new()
        }
    }

    /// Get neighbors of a node
    pub fn neighbors(&self, node_id: NodeId) -> Result<Vec<NodeId>> {
        let node_index = *self.node_indices.get(&node_id).ok_or_else(|| {
            CodeGraphError::graph_update_error(format!("Node {} not found", node_id))
        })?;

        let graph = self.graph.read().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire graph read lock")
        })?;

        let neighbors: Vec<NodeId> = graph
            .neighbors(node_index)
            .map(|idx| graph[idx])
            .collect();

        Ok(neighbors)
    }

    /// Get incoming edges for a node
    pub fn incoming_edges(&self, node_id: NodeId) -> Result<Vec<EdgeId>> {
        let node_index = *self.node_indices.get(&node_id).ok_or_else(|| {
            CodeGraphError::graph_update_error(format!("Node {} not found", node_id))
        })?;

        let graph = self.graph.read().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire graph read lock")
        })?;

        let edges: Vec<EdgeId> = graph
            .edges_directed(node_index, petgraph::Incoming)
            .map(|edge_ref| graph[edge_ref.id()])
            .collect();

        Ok(edges)
    }

    /// Get outgoing edges for a node
    pub fn outgoing_edges(&self, node_id: NodeId) -> Result<Vec<EdgeId>> {
        let node_index = *self.node_indices.get(&node_id).ok_or_else(|| {
            CodeGraphError::graph_update_error(format!("Node {} not found", node_id))
        })?;

        let graph = self.graph.read().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire graph read lock")
        })?;

        let edges: Vec<EdgeId> = graph
            .edges_directed(node_index, petgraph::Outgoing)
            .map(|edge_ref| graph[edge_ref.id()])
            .collect();

        Ok(edges)
    }

    /// Get graph statistics
    pub fn node_count(&self) -> usize {
        self.metadata.node_count
    }

    /// Get edge count
    pub fn edge_count(&self) -> usize {
        self.metadata.edge_count
    }

    /// Get supported languages
    pub fn languages(&self) -> Vec<String> {
        self.metadata.languages.iter().cloned().collect()
    }

    /// Get node types present in the graph
    pub fn node_types(&self) -> Vec<NodeType> {
        self.metadata.node_types.iter().cloned().collect()
    }

    /// Get edge types present in the graph
    pub fn edge_types(&self) -> Vec<EdgeType> {
        self.metadata.edge_types.iter().cloned().collect()
    }

    /// Get graph metadata
    pub fn metadata(&self) -> &GraphMetadata {
        &self.metadata
    }

    /// Update graph statistics
    pub fn update_statistics(&mut self) -> Result<()> {
        let graph = self.graph.read().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire graph read lock")
        })?;

        let node_count = graph.node_count();
        let edge_count = graph.edge_count();

        // Calculate average degree
        let average_degree = if node_count > 0 {
            (2 * edge_count) as f64 / node_count as f64
        } else {
            0.0
        };

        // Calculate density
        let max_edges = if node_count > 1 {
            node_count * (node_count - 1)
        } else {
            1
        };
        let density = edge_count as f64 / max_edges as f64;

        // Calculate connected components (simplified)
        let connected_components = petgraph::algo::connected_components(&*graph);

        // Update statistics
        self.metadata.stats = GraphStats {
            average_degree,
            density,
            connected_components,
            diameter: None, // TODO: Implement diameter calculation
            clustering_coefficient: 0.0, // TODO: Implement clustering coefficient
        };

        self.metadata.modified_at = chrono::Utc::now();
        Ok(())
    }

    /// Clear the graph
    pub fn clear(&mut self) {
        let mut graph = self.graph.write().unwrap();
        graph.clear();
        drop(graph);

        self.nodes.clear();
        self.edges.clear();
        self.node_indices.clear();
        self.edge_indices.clear();
        self.language_nodes.clear();
        self.type_nodes.clear();

        let now = chrono::Utc::now();
        self.metadata = GraphMetadata {
            created_at: self.metadata.created_at,
            modified_at: now,
            version: self.metadata.version + 1,
            node_count: 0,
            edge_count: 0,
            languages: HashSet::new(),
            node_types: HashSet::new(),
            edge_types: HashSet::new(),
            stats: GraphStats::default(),
        };
    }

    /// Check if the graph is empty
    pub fn is_empty(&self) -> bool {
        self.metadata.node_count == 0
    }

    /// Find shortest path between two nodes
    pub fn shortest_path(&self, source: NodeId, target: NodeId) -> Result<Option<Vec<NodeId>>> {
        let source_index = *self.node_indices.get(&source).ok_or_else(|| {
            CodeGraphError::graph_update_error(format!("Source node {} not found", source))
        })?;
        let target_index = *self.node_indices.get(&target).ok_or_else(|| {
            CodeGraphError::graph_update_error(format!("Target node {} not found", target))
        })?;

        let graph = self.graph.read().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire graph read lock")
        })?;

        let path = petgraph::algo::dijkstra(&*graph, source_index, Some(target_index), |_| 1);

        if path.contains_key(&target_index) {
            // Reconstruct path (simplified - just return the nodes)
            let mut result = Vec::new();
            result.push(source);
            result.push(target);
            Ok(Some(result))
        } else {
            Ok(None)
        }
    }

    /// Execute a basic query on the graph
    pub fn query(&self, query: &GraphQuery) -> Result<QueryResult> {
        let mut result_nodes = Vec::new();
        let mut result_edges = Vec::new();

        // Filter nodes by type
        if let Some(ref node_types) = query.node_types {
            for node_type in node_types {
                if let Some(type_nodes) = self.type_nodes.get(node_type) {
                    result_nodes.extend(type_nodes.iter().cloned());
                }
            }
        } else {
            // Include all nodes if no type filter
            result_nodes.extend(self.nodes.iter().map(|entry| *entry.key()));
        }

        // Filter by language
        if let Some(ref languages) = query.languages {
            let mut filtered_nodes = Vec::new();
            for language in languages {
                if let Some(lang_nodes) = self.language_nodes.get(language) {
                    for node_id in &result_nodes {
                        if lang_nodes.contains(node_id) {
                            filtered_nodes.push(*node_id);
                        }
                    }
                }
            }
            result_nodes = filtered_nodes;
        }

        // Apply limit and offset
        if let Some(offset) = query.offset {
            if offset < result_nodes.len() {
                result_nodes = result_nodes[offset..].to_vec();
            } else {
                result_nodes.clear();
            }
        }

        if let Some(limit) = query.limit {
            result_nodes.truncate(limit);
        }

        // Get relevant edges
        for node_id in &result_nodes {
            if let Ok(outgoing) = self.outgoing_edges(*node_id) {
                result_edges.extend(outgoing);
            }
        }

        Ok(QueryResult {
            nodes: result_nodes,
            edges: result_edges,
            metadata: std::collections::HashMap::new(),
            execution_time_ms: 0, // TODO: Implement timing
        })
    }

    // ===== BATCH OPERATIONS FOR PERFORMANCE OPTIMIZATION =====

    /// Batch add multiple nodes for improved performance
    pub fn add_nodes_batch(&mut self, nodes: Vec<GraphNode>) -> Result<Vec<NodeId>> {
        let start_time = Instant::now();
        let mut node_ids = Vec::with_capacity(nodes.len());
        let mut language_updates: HashMap<String, Vec<NodeId>> = HashMap::new();
        let mut type_updates: HashMap<NodeType, Vec<NodeId>> = HashMap::new();

        info!("Starting batch node addition: {} nodes", nodes.len());

        // Acquire graph write lock once for the entire batch
        let mut graph = self.graph.write().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire graph write lock")
        })?;

        for node in nodes {
            let node_id = node.id();
            let language = node.language().to_string();
            let node_type = node.node_type().clone();

            // Add to petgraph
            let node_index = graph.add_node(node_id);

            // Store mappings
            self.node_indices.insert(node_id, node_index);

            // Collect language and type updates for batch processing
            language_updates.entry(language.clone()).or_insert_with(Vec::new).push(node_id);
            type_updates.entry(node_type.clone()).or_insert_with(Vec::new).push(node_id);

            // Store the node
            self.nodes.insert(node_id, Arc::new(RwLock::new(node)));

            // Update metadata languages and types
            self.metadata.languages.insert(language);
            self.metadata.node_types.insert(node_type);

            node_ids.push(node_id);
        }

        // Release graph lock early
        drop(graph);

        // Batch update language groupings
        for (language, node_list) in language_updates {
            let mut lang_nodes = self.language_nodes.entry(language).or_insert_with(HashSet::new);
            for node_id in node_list {
                lang_nodes.insert(node_id);
            }
        }

        // Batch update type groupings
        for (node_type, node_list) in type_updates {
            let mut type_nodes = self.type_nodes.entry(node_type).or_insert_with(HashSet::new);
            for node_id in node_list {
                type_nodes.insert(node_id);
            }
        }

        // Update metadata
        self.metadata.modified_at = chrono::Utc::now();
        self.metadata.version += 1;
        self.metadata.node_count += node_ids.len();

        let duration = start_time.elapsed();
        info!("Batch node addition completed: {} nodes in {}ms",
              node_ids.len(), duration.as_millis());

        Ok(node_ids)
    }

    /// Batch add multiple edges for improved performance
    pub fn add_edges_batch(&mut self, edges: Vec<GraphEdge>) -> Result<Vec<EdgeId>> {
        let start_time = Instant::now();
        let mut edge_ids = Vec::with_capacity(edges.len());
        let mut edge_types_set = HashSet::new();

        info!("Starting batch edge addition: {} edges", edges.len());

        // Pre-validate all edges to avoid partial failures
        for edge in &edges {
            let source_id = edge.source();
            let target_id = edge.target();

            if !self.nodes.contains_key(&source_id) {
                return Err(CodeGraphError::graph_update_error(
                    format!("Source node {} not found", source_id)
                ));
            }
            if !self.nodes.contains_key(&target_id) {
                return Err(CodeGraphError::graph_update_error(
                    format!("Target node {} not found", target_id)
                ));
            }
        }

        // Acquire graph write lock once for the entire batch
        let mut graph = self.graph.write().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire graph write lock")
        })?;

        for edge in edges {
            let edge_id = edge.id();
            let source_id = edge.source();
            let target_id = edge.target();
            let edge_type = edge.edge_type().clone();

            // Get node indices (we already validated they exist)
            let source_index = *self.node_indices.get(&source_id).unwrap();
            let target_index = *self.node_indices.get(&target_id).unwrap();

            // Add to petgraph
            let edge_index = graph.add_edge(source_index, target_index, edge_id);

            // Store mappings
            self.edge_indices.insert(edge_id, edge_index);

            // Store the edge
            self.edges.insert(edge_id, Arc::new(RwLock::new(edge)));

            edge_types_set.insert(edge_type);
            edge_ids.push(edge_id);
        }

        // Release graph lock early
        drop(graph);

        // Update metadata
        self.metadata.modified_at = chrono::Utc::now();
        self.metadata.version += 1;
        self.metadata.edge_count += edge_ids.len();
        self.metadata.edge_types.extend(edge_types_set);

        let duration = start_time.elapsed();
        info!("Batch edge addition completed: {} edges in {}ms",
              edge_ids.len(), duration.as_millis());

        Ok(edge_ids)
    }

    /// Batch remove multiple nodes for improved performance
    pub fn remove_nodes_batch(&mut self, node_ids: Vec<NodeId>) -> Result<usize> {
        let start_time = Instant::now();
        let mut removed_count = 0;
        let mut language_updates: HashMap<String, Vec<NodeId>> = HashMap::new();
        let mut type_updates: HashMap<NodeType, Vec<NodeId>> = HashMap::new();

        info!("Starting batch node removal: {} nodes", node_ids.len());

        // Collect node information before removal
        for node_id in &node_ids {
            if let Some(node) = self.nodes.get(node_id) {
                let node_guard = node.read().map_err(|_| {
                    CodeGraphError::graph_update_error("Failed to acquire node read lock")
                })?;
                let language = node_guard.language().to_string();
                let node_type = node_guard.node_type().clone();

                language_updates.entry(language).or_insert_with(Vec::new).push(*node_id);
                type_updates.entry(node_type).or_insert_with(Vec::new).push(*node_id);
            }
        }

        // Acquire graph write lock once for the entire batch
        let mut graph = self.graph.write().map_err(|_| {
            CodeGraphError::graph_update_error("Failed to acquire graph write lock")
        })?;

        for node_id in node_ids {
            if let Some(node_index) = self.node_indices.get(&node_id) {
                let node_index = *node_index;

                // Remove from petgraph (this also removes connected edges)
                if graph.remove_node(node_index).is_some() {
                    // Remove from storage
                    self.nodes.remove(&node_id);
                    self.node_indices.remove(&node_id);
                    removed_count += 1;
                }
            }
        }

        // Release graph lock early
        drop(graph);

        // Batch update language groupings
        for (language, node_list) in language_updates {
            if let Some(mut lang_nodes) = self.language_nodes.get_mut(&language) {
                for node_id in node_list {
                    lang_nodes.remove(&node_id);
                }
            }
        }

        // Batch update type groupings
        for (node_type, node_list) in type_updates {
            if let Some(mut type_nodes) = self.type_nodes.get_mut(&node_type) {
                for node_id in node_list {
                    type_nodes.remove(&node_id);
                }
            }
        }

        // Update metadata
        self.metadata.modified_at = chrono::Utc::now();
        self.metadata.version += 1;
        self.metadata.node_count = self.metadata.node_count.saturating_sub(removed_count);

        let duration = start_time.elapsed();
        info!("Batch node removal completed: {} nodes in {}ms",
              removed_count, duration.as_millis());

        Ok(removed_count)
    }
}

impl Default for CodeGraph {
    fn default() -> Self {
        Self::new()
    }
}
